Introducción a R

Resumen

En el presente documento se da una breve introducción al lenguaje R. Exploraremos desde las funciones más básicas del lenguaje (como leer tablas de datos, hacer aritmética, algunas operaciones algebraicas) hasta cómo utilizar funciones de paquetes especializados para el análisis espacial (i.e. raster, rgdal, dismo). También se hará énfansis en cómo programar funciones propias o funciones definidas por el usuario (helper functions) las cuales tienen el objetivo de facilitarnos tareas complejas. Es importante notar que operaciones básicas como la indexación suelen ser vitales para poder realizar operaciones mucho más complicadas y complejas dentro de los loops y estructuras de control.

Qué es, de dónde y cómo instalo R?

R es un lenguaje de programación de código abierto el cual está basado en el lenguaje S. En sus inicios el lenguaje realizaba solo operaciones estadísticas y gráficas, sin embargo a través de los años se ha convertido en un lenguaje polifacético en donde podemos encontrar desde paquetes para el análisis de textos (text mining), web scraping, análisis espaciales (i.e. spatstat) hasta para la programación de aplicaciones web (i.e shiny). Lo anterior se debe a que varios de sus usuarios se han convertido en desarrolladores activos de la comunidad. Acutualmente existen casi 13000 paquetes (Fig. 1), el crecimiento de estos ha sido exponencial (Fig. 2).

Figura_1

Figura 1. Número de paquetes en CRAN

Figura 2. Serie de tiempo del número de paquetes en CRAN

Obtención e instalación de R

R se puede descargar de la siguiente página web http://www.r-project.org/. Figura_3

En el panel izquierdo encontrarás la opción de download donde elegirás un mirror para descargarlo, los links para México son los siguientes:

Elige el link de descarga que te parezca más adecuado en función del área en que te encuentres. Una vez elegido el mirror, selecciona la versión de R de acuerdo a tu sistema operativo (Linux, Mac o Windows).

Figura_4

Figura_4

La forma más fácil de instalar R es por medio de los binarios (o ejecutables), sin embargo si deseas instalarlo desde teminal de Linux o Mac aquí puedes encontrar las instrucciones:

Antes de empezar con el tutorial voy a fijar una semilla aleatoria para que los ejemplos de este documento sean reproducibles (es decir, para que todos en el grupo lleguen a los mismos resultados).

Tutorial: Introducción a R

Una vez que han instalado R en sus computadoras ahora estamos listos para comenzar a aprender programación en este ambiente maravilloso.

Sintaxis

La primera cosa que hay que explorar es la sintaxis del lenguaje; en esta sección daremos un panorama general de ella. La primera cosa que hay que tener en cuenta sobre la sintaxis de R es que a diferencia de otros lenguajes como SQL, BASIC, Pascal, R es sensible a mayúsculas y minúsculas por lo que un objeto llamado libro es diferente a Libro. Veamos el ejemplo:

## [1] TRUE
## [1] FALSE

A pesar de que no se comentó anteriormente (se dio por hecho), en R la forma de declarar variables es mediante el comando de asignación (<-). Aunque también es posible declarar las variables con el signo (=) se recomienda usar <-. Veremos más sobre variables en las siguientes secciones

## [1] 1
## [1] 2
## [1] 3

Otra característica de la sintaxis es que en R solo se permite nombrar a las variables comenzando con letras (mayúsculas o minúsculas) o “.”* y nunca con números.

## [1] "Dulce"
## [1] "Agradable"

Las variables pueden contener números en cualquier otra posición (nunca al comienzo).

## [1] "fresco"
## [1] "fresco"

Ahora probemos con el “.”*

## [1] "SOS"

R como calculadora

La consola de R puede ser usada como calculadora aritmética, vemos algunas operaciones básicas:

Una suma

## [1] 94

Una resta

## [1] -149

Una multiplicación

## [1] 196

División

## [1] 1.2

Potencia

## [1] 387420489

El residuo de la división

## [1] 2

La parte entera

## [1] 1

Podemos verificar que 9 es la suma de su residuo más 7 veces la parte entera de la fracción

## [1] 9

Los paréntesis puede ser usados para especificar el orden de las operaciones

## [1] 2.713765

R contiene algunas funciones matemáticas ya incluidas como \(\sin(x)\), \(\cos(x)\), \(\tan(x)\), (en radianes), \(\exp(x)\), \(\log(x)\) y \(\sqrt{x}\).

## [1] 2.718282
## [1] 0.841471
## [1] 0.5403023
## [1] 0
## [1] 1

También tiene en memoria algunas constantes como \(\pi\)

## [1] 3.141593

Podemos especificar la precisión de las salidas con el comando options

## [1] 3.141592653589793

Redondear cantidades

## [1] 2.94
## [1] 1
## [1] 0

Variables (Global environment)

R tiene un ambiente de trabajo conocido como ambiente global (Global environment) en donde se guardan los resultados de los cálculos. Los resultados se guardan en forma de objetos o variables; una variable es como un folder etiquetado donde guardamos documentos, éstos puede ser de diversa naturaleza y siempre tenemos la opción de cambiar el contenido de ellos, sin embargo, el folder se llamará de la misma manera.

Las variables globales se encuentran en el Global environment y pueden ser llamadas en cualquier momento durante la sesión; así, si quisiéramos almacenar una cantidad, digamos la tasa de interés anual a la que pagaremos un coche, podemos guardarla en la variable i.e. tasa_anual y utilizarla cuando la necesitemos.

Imaginemos que vamos a comprar un Audi RS5 4.2 FSI 450 hp y que queremos pagarlo a 48 meses (4 años). La tasa anual que maneja audi es aproximadamente de 12.9%; olvidándonos de los pagos de comisión por apertura etc. hagamos el cálculo de cuánto pagaremos por nuestro Audi (Fig. 5).

figura_5

Figura 5. Audi RS5 4.2 FSI 450 hp

## [1] 191552.1
## [1] 766208.4
## [1] 2251108.4

Los vectores y matrices en R

Comencemos con algunas definiciones necesarias:

  • Escalar: Un escalar es sólo una cantidad numérica i.e. un entero o un número real.
  • Vector \(v \in R^n\) : Se llama vector de dimensión \(n\) a una tupla de \(n\) números reales o componentes del vector (un vector está constituido por 1 o varios escalares).

El conjunto de todos los vectores de dimensión \(n\), se representa como \(\mathbb{R}^n\). Así, un vector \({\textbf v}\) perteneciente a un espacio \(\mathbb{R}^n\) se representa como:

\({\textbf v} = (a_1, a_2, a_3, \dots, a_n)\) donde \({\textbf v} \in \mathbb{R}^n\)

En matemáticas existen dos tipos de vectores, el vector renglón (el de la ecuación de arriba) y el vector columna.

Vector columna

\[\textbf v= \left( \begin{array}{c} a_1\\ a_2\\ \vdots\\ a_n\\ \end{array} \right)\]

Para saber más sobre las operaciones matemáticas de vectores y matrices en R da clic aquí.

Indexación de vectores en R

Nótese que se puede localizar a cada componente del vector por su posición (ver ejemplo).

\[\textbf f = (5,2,4,3)\]

De modo que la componente 3 del vector \(\textbf f\) es el número \(4\). En R, a lo anterior se le denomina indexación y es una de las herramientas más poderosas que podemos aprender; si logramos dominar este arte, la programación y automatización de tareas muy complejas será mucho más sencilla.

El desconocimiento de la forma en cómo se indexan los vectores o matrices hace que el código fuente de los programas o scripts sea obscuro. En los siguientes ejemplos veremos que esta arte es mucho más clara de lo que parece.

Primero debemos notar que en R la forma más básica de construir vectores es utilizando la función concatenar “c”. Este comando concatena a cada uno de los elementos que formarán a nuestro vector.

Comprobemos si efectivamente el elemento 3 del vector \({\textbf f}\) es el número \(4\)

## [1] 4

Efectivamente es el número 4 y que hay del primer elemento?

## [1] 5

Si quisiéramos extraer más de un elemento (un subconjunto \(\textbf f_1\) de dimensión \(m\) con \(m \le n\)) del vector \({\textbf f}\)?

Ahora se muestra como formar un subconjunto \(\textbf f_1\) constituido por los elementos 1, 3 y 4 del vector \({\textbf f}\)

## [1] 5 4 3

Nota: En algunos lenguajes como python la indexación comienza con el 0.

Generación de secuencias (vectores) regulares en R

R tiene varias formas de generar secuencias, por ejemplo, el comando 1:n genera la secuencia \(1,2,3,\dots,n\). La secuencia anterior es una de las más utilizadas para generar subconjuntos de vectores de dimensión \(n\) y cuyos elementos son números enteros.

##  [1]  1  2  3  4  5  6  7  8  9 10

Otro comando que encontraremos con frecuencia es el comando “seq”, este comando genera secuencias de números en el intervalo \([a,b]\) con particiones de tamaño \(\delta\).

Generemos una secuencia de números del 0 al 10 de 2 en 2, es decir \(\delta=2\)

## [1]  0  2  4  6  8 10

Ahora una secuencia de 0 a 1 con \(\delta=0.01\)

##   [1] 0.00000000000000000 0.01000000000000000 0.02000000000000000
##   [4] 0.03000000000000000 0.04000000000000000 0.05000000000000000
##   [7] 0.06000000000000000 0.07000000000000001 0.08000000000000000
##  [10] 0.09000000000000000 0.10000000000000001 0.11000000000000000
##  [13] 0.12000000000000000 0.13000000000000000 0.14000000000000001
##  [16] 0.14999999999999999 0.16000000000000000 0.17000000000000001
##  [19] 0.17999999999999999 0.19000000000000000 0.20000000000000001
##  [22] 0.20999999999999999 0.22000000000000000 0.23000000000000001
##  [25] 0.23999999999999999 0.25000000000000000 0.26000000000000001
##  [28] 0.27000000000000002 0.28000000000000003 0.28999999999999998
##  [31] 0.29999999999999999 0.31000000000000000 0.32000000000000001
##  [34] 0.33000000000000002 0.34000000000000002 0.35000000000000003
##  [37] 0.35999999999999999 0.37000000000000000 0.38000000000000000
##  [40] 0.39000000000000001 0.40000000000000002 0.41000000000000003
##  [43] 0.41999999999999998 0.42999999999999999 0.44000000000000000
##  [46] 0.45000000000000001 0.46000000000000002 0.47000000000000003
##  [49] 0.47999999999999998 0.48999999999999999 0.50000000000000000
##  [52] 0.51000000000000001 0.52000000000000002 0.53000000000000003
##  [55] 0.54000000000000004 0.55000000000000004 0.56000000000000005
##  [58] 0.57000000000000006 0.57999999999999996 0.58999999999999997
##  [61] 0.59999999999999998 0.60999999999999999 0.62000000000000000
##  [64] 0.63000000000000000 0.64000000000000001 0.65000000000000002
##  [67] 0.66000000000000003 0.67000000000000004 0.68000000000000005
##  [70] 0.69000000000000006 0.70000000000000007 0.70999999999999996
##  [73] 0.71999999999999997 0.72999999999999998 0.73999999999999999
##  [76] 0.75000000000000000 0.76000000000000001 0.77000000000000002
##  [79] 0.78000000000000003 0.79000000000000004 0.80000000000000004
##  [82] 0.81000000000000005 0.82000000000000006 0.83000000000000007
##  [85] 0.83999999999999997 0.84999999999999998 0.85999999999999999
##  [88] 0.87000000000000000 0.88000000000000000 0.89000000000000001
##  [91] 0.90000000000000002 0.91000000000000003 0.92000000000000004
##  [94] 0.93000000000000005 0.94000000000000006 0.95000000000000007
##  [97] 0.95999999999999996 0.96999999999999997 0.97999999999999998
## [100] 0.98999999999999999 1.00000000000000000

Imaginemos que se quiere una secuencia de números definidos en el intervalo \((13,25)\) pero cuya longitud sea de 40 números. Uno de los argumentos del comando seq es length.out y con este se puede especificar la longitud de la secuencia de valores que queremos generar.

##  [1] 13.00000000000000 13.30769230769231 13.61538461538461
##  [4] 13.92307692307692 14.23076923076923 14.53846153846154
##  [7] 14.84615384615385 15.15384615384615 15.46153846153846
## [10] 15.76923076923077 16.07692307692308 16.38461538461539
## [13] 16.69230769230769 17.00000000000000 17.30769230769231
## [16] 17.61538461538462 17.92307692307692 18.23076923076923
## [19] 18.53846153846154 18.84615384615385 19.15384615384615
## [22] 19.46153846153846 19.76923076923077 20.07692307692308
## [25] 20.38461538461539 20.69230769230769 21.00000000000000
## [28] 21.30769230769231 21.61538461538462 21.92307692307692
## [31] 22.23076923076923 22.53846153846154 22.84615384615385
## [34] 23.15384615384615 23.46153846153846 23.76923076923077
## [37] 24.07692307692308 24.38461538461539 24.69230769230769
## [40] 25.00000000000000

El comando rep

La función rep permite generar secuencias repetidas de vectores.

## [1] "A" "B" "A" "B"

El comando sample

Un comando frecuentemente utilizado para extraer una muestra aleatoria de un vector el comando sample. Algunos de sus argumentos son:

  • El vector de donde se va a sacar la secuencia aleatoria (\(x\)).
  • El número de elementos (size) que se van a extraer del vector \(x\).
  • La muestra será obtenida con remplazo (replace)

En el siguiente ejemplo crearemos un vector de 1000 elementos y tomaremos una muestra aleatoria de 100. Veamos cómo hacerlo en R!

##   [1] 593 726 370 514 377 417  11 529 429  93 551 584  67  47 155 440 169
##  [18] 951 306 603 423 280 335 378 945 314 637 276 766 579  57 495 451 454
##  [35] 348 689 113 755 618 774 616 316 609 889 550 351 995 816 598 963 965
##  [52] 556  32 959 943 519 544 431  91 759   1 439 163 243 861 217  50 284
##  [69] 994 979 817 619 422 934 585 410 248 909  88 724 111 810 121 368  80
##  [86] 343 626 671 704 993 466 776 572 526 913 955 899 360 880 743

Midiendo la longitud de un vector

Supongamos que estamos creando un algoritmo donde en uno de los pasos se genera un vector \(\textbf l\) cuyo tamaño puede variar en función de que se cumpla una condición \(c\); imaginemos que estamos interesados en saber cuál es el número promedio de iteraciones que necesita nuestro algoritmo para cumplir la condición \(c\). Una forma de averiguar lo anterior es guardar en un vector n_iter el número de iteraciones que el algoritmo necesitó en cada una de las simulaciones que relizamos. La pregunta es cómo saber la longitud del vector \(\textbf l\): en R es muy sencillo, el comando para realizarlo es length

## [1] 18

Las matrices en R

  • Matriz: Es un arreglo bidimensional de números donde cada elemento de la matriz \(\textbf M\) se puede identidficar por la fila \(i\) y la columna \(j\) a la que pertenece.

En R las matrices pueden ser de 2 tipos:

  1. Numérica
  2. Cadena

Lo anterior quiere decir que no podemos combinar números con caracteres. Si fuera este el caso, R internamente realiza una operación conocida como casteo cast y convierte a todos los elementos a caracteres (strings)

Creación de matrices en R

Las matrices en R se crean con el comando matrix y sólo necesitamos indicar los elementos que la conformarán (data), el número de filas (nrow) y columnas (ncol) que contendrá.

##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16

Como se había mencionado las matrices en R sólo pueden ser de dos tipos numéricas o de cadena de caracteres:

Tratemos de combinar números con letras

##      [,1] [,2] [,3] [,4]
## [1,] "A"  "E"  "1"  "5" 
## [2,] "B"  "F"  "2"  "6" 
## [3,] "C"  "G"  "3"  "7" 
## [4,] "D"  "H"  "4"  "8"

Indexación de matrices en R

Sea \(\textbf M\) una matriz de \(6\times 8\) dimensiones. Supongamos que se nos pide extraer el elemento que corresponde a la fila 3 y al renglón 6. La forma de indexar matrices en R sigue la misma lógica que en matemáticas en donde \(\mathbf{M_{fila,columna}}\) en R se indexa como \(\mathbf{M[fila,columna]}\). Veamos el código!

## [1] 2.893617021276595

También podemos usar la indexación para mostrar una sola fila de la matriz, una columna completa, los primeros \(m\) elementos de una fila o una columna, las primeras \(k\) columnas y las primeras \(r\) filas de la matriz…

Llamando sólo una fila de una matriz

A continuación se muestra como enlistar la segunda fila de la matriz \(\mathbf M\)

## [1] 2.340425531914894 2.382978723404255 2.425531914893617 2.468085106382979
## [5] 2.510638297872340 2.553191489361702 2.595744680851064 2.638297872340425

Llamando sólo una columna de una matriz

A continuación se muestra como enlistar la tercera columna de la matriz \(\mathbf M\)

## [1] 2.085106382978724 2.425531914893617 2.765957446808510 3.106382978723405
## [5] 3.446808510638298 3.787234042553191

Combinando formas de indexar

Con las operaciones vistas hasta el momento podemos realizar varias combinaciones para extraer elementos de una matriz. Veamos algunos ejemplos de lo anterior.

Dada la matriz \(\mathbf {M_{5,5}}\) extraer:

  1. las primeras 3 filas de las columnas 1 y 2
##      [,1] [,2]
## [1,]    1    2
## [2,]    6    7
## [3,]   11   12
  1. Las filas de 1 a la 5 de las columas 1 y 5
##      [,1] [,2]
## [1,]    1    5
## [2,]    6   10
## [3,]   11   15
## [4,]   16   20
## [5,]   21   25

Para saber más sobre matrices y sus operaciones en R da clic aquí.

Los data.frame

Al igual que las matrices, un data.frame es un arreglo bidimensional de reglones y columnas. A diferencia de las matrices este permite tener columnas de tipo numérico y de tipo caracter en él. Cada columna representa una variable (en el sentido estadístico).

Construcción de data.frames

La función data.frame permite contruir un data.frame a partir de vectores; cada vector representa una variable o columna en el data.frame. A continuación veremos cómo construir un data.frame cuyas variables son de tipo numérico y de tipo caracter.

Pollitos

Construiremos una tabla de datos (data.frame) que tenga información sobre 5 lotes de 15 pollitos a los cuales daremos un identificador a nivel individuo y a nivel lote y también llevaramos un registro de su peso. El peso inicial promedio de los pollitos es de \(10 \pm 2\) gramos

pollito_id lote peso_inicial
1 1 L1 8.544862350448966
2 2 L1 11.758935921825469
3 3 L1 8.705138908699155
21 21 L2 10.723021856509149
22 22 L2 11.703913740813732
23 23 L2 10.534392120316625
31 31 L3 10.468478028662503
32 32 L3 10.320646803826094
33 33 L3 11.767220824025571
51 51 L4 9.056855553761125
52 52 L4 9.055385123938322
53 53 L4 8.361524064093828
71 71 L5 10.047071536071599
72 72 L5 10.666186263784766
73 73 L5 8.106038851663470

Agregando datos al data.frame

Supóngase que a cada lote de pollitos se les alimenta con una dieta diferente durante 45 días, por lo tanto será necesario agregar la vairable dieta a nuestra tabla de datos.

También la variable peso después de los 45 días de engorde.

pollito_id lote peso_inicial Dieta peso_dieta
1 1 L1 8.544862350448966 D1 2249.397271513513
2 2 L1 11.758935921825469 D1 2250.660069387382
3 3 L1 8.705138908699155 D1 2252.050749526114
21 21 L2 10.723021856509149 D2 2602.428160185903
22 22 L2 11.703913740813732 D2 2599.510209257107
23 23 L2 10.534392120316625 D2 2601.678859712361
31 31 L3 10.468478028662503 D3 1802.638324892332
32 32 L3 10.320646803826094 D3 1801.181974725185
33 33 L3 11.767220824025571 D3 1802.066776451425
51 51 L4 9.056855553761125 D4 2100.258924159411
52 52 L4 9.055385123938322 D4 2099.637606327696
53 53 L4 8.361524064093828 D4 2100.404668015637
71 71 L5 10.047071536071599 D5 1997.980726526860
72 72 L5 10.666186263784766 D5 2001.064923304782
73 73 L5 8.106038851663470 D5 2000.614799222425

Indexación de data.frames

La indexación de los data.frames es idéntica al de las matrices; sin embargo, tiene una ventaja adicional, esta ventaja radica en que podemos llamar una columana completa indicando el nombre de esta en vez del número. De este modo en el ejemplo de pollitos, no importa si no sabemos la posición exacta de la columna dieta R la encontrará por nosotros.

Veamos como hacerlo, imprimamos los primeros 10 elementos de la columana dieta

##  [1] "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1"

Otra forma de realizar la operación anterior es utilizando el símbolo de \(\$\)

##  [1] "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1" "D1"

Las listas

Es momento de introducir a uno de los objetos estrella de R, este es el objeto lista. Al igual que los vectores, las listas son arreglos unidimensionales con la peculiaridad de que los elementos que las integran pueden ser de varias clases, por ejemplo, data.frames, matrices, vectores, rasters, etc. A continuación veamos cómo crear una lista que contiene como elementos un data.frame, un vector y una lista, esta se crea con el comando list()

## $vector
##  [1] 0.8176385075785220 0.8938548327423632 0.6814558403566480
##  [4] 0.4533687653020024 0.6515468196012080 0.7260923418216407
##  [7] 0.6991440386045724 0.5504099403042346 0.8171223362442106
## [10] 0.2699587242677808
## 
## $pollitos_df
##    pollito_id lote       peso_inicial Dieta        peso_dieta
## 1           1   L1  8.544862350448966    D1 2249.397271513513
## 2           2   L1 11.758935921825469    D1 2250.660069387382
## 3           3   L1  8.705138908699155    D1 2252.050749526114
## 4           4   L1 11.278820903971791    D1 2250.490808178818
## 5           5   L1  8.048473510891199    D1 2248.268520581220
## 6           6   L1 10.560249282047153    D1 2250.710883659408
## 7           7   L1  9.068114688619971    D1 2250.013822911462
## 8           8   L1 10.277991003356874    D1 2248.598958402634
## 9           9   L1 11.861210129223764    D1 2251.259123665442
## 10         10   L1  8.793691774830222    D1 2249.872522481624
## 
## $sublista
## $sublista$a
##  [1]  1  2  3  4  5  6  7  8  9 10

Extracción de los elementos de la lista

Como habíamos visto en la sección anterior, las listas se comportan como vectores y por tanto la forma de extraer un elemento de esta simplemente es ocupando la sintaxis lista[[element_index]].

pollito_id lote peso_inicial Dieta peso_dieta
1 L1 8.544862350448966 D1 2249.397271513513
2 L1 11.758935921825469 D1 2250.660069387382
3 L1 8.705138908699155 D1 2252.050749526114
4 L1 11.278820903971791 D1 2250.490808178818
5 L1 8.048473510891199 D1 2248.268520581220
6 L1 10.560249282047153 D1 2250.710883659408
7 L1 9.068114688619971 D1 2250.013822911462
8 L1 10.277991003356874 D1 2248.598958402634
9 L1 11.861210129223764 D1 2251.259123665442
10 L1 8.793691774830222 D1 2249.872522481624

Otra forma de extraer un elemento de la lista es con la sintaxis lista$nombre_elemento

pollito_id lote peso_inicial Dieta peso_dieta
1 L1 8.544862350448966 D1 2249.397271513513
2 L1 11.758935921825469 D1 2250.660069387382
3 L1 8.705138908699155 D1 2252.050749526114
4 L1 11.278820903971791 D1 2250.490808178818
5 L1 8.048473510891199 D1 2248.268520581220
6 L1 10.560249282047153 D1 2250.710883659408
7 L1 9.068114688619971 D1 2250.013822911462
8 L1 10.277991003356874 D1 2248.598958402634
9 L1 11.861210129223764 D1 2251.259123665442
10 L1 8.793691774830222 D1 2249.872522481624

o bien lista[["nombre_elemento"]]

pollito_id lote peso_inicial Dieta peso_dieta
1 L1 8.544862350448966 D1 2249.397271513513
2 L1 11.758935921825469 D1 2250.660069387382
3 L1 8.705138908699155 D1 2252.050749526114
4 L1 11.278820903971791 D1 2250.490808178818
5 L1 8.048473510891199 D1 2248.268520581220
6 L1 10.560249282047153 D1 2250.710883659408
7 L1 9.068114688619971 D1 2250.013822911462
8 L1 10.277991003356874 D1 2248.598958402634
9 L1 11.861210129223764 D1 2251.259123665442
10 L1 8.793691774830222 D1 2249.872522481624

Extrayendo elementos contenidos en una lista de listas

Estamos interesados en extaer el elemento 10 del vector a contenido en la lista nombrada sublista que se encuentra dentro de nuestra lista principal. La sintaxis para extraer un elemento de una lista contenida dentro de otra lista es lista[[indice_nivel_1]][[indice_nivel_2]][[indice_nivel3]]

## [1] 10

o bien

## [1] 10

Agregando nuevos elementos a una lista

Agreguemos un nuevo elemento (un vector de números aleatorios) a lista

## $vector
##  [1] 0.8176385075785220 0.8938548327423632 0.6814558403566480
##  [4] 0.4533687653020024 0.6515468196012080 0.7260923418216407
##  [7] 0.6991440386045724 0.5504099403042346 0.8171223362442106
## [10] 0.2699587242677808
## 
## $pollitos_df
##    pollito_id lote       peso_inicial Dieta        peso_dieta
## 1           1   L1  8.544862350448966    D1 2249.397271513513
## 2           2   L1 11.758935921825469    D1 2250.660069387382
## 3           3   L1  8.705138908699155    D1 2252.050749526114
## 4           4   L1 11.278820903971791    D1 2250.490808178818
## 5           5   L1  8.048473510891199    D1 2248.268520581220
## 6           6   L1 10.560249282047153    D1 2250.710883659408
## 7           7   L1  9.068114688619971    D1 2250.013822911462
## 8           8   L1 10.277991003356874    D1 2248.598958402634
## 9           9   L1 11.861210129223764    D1 2251.259123665442
## 10         10   L1  8.793691774830222    D1 2249.872522481624
## 
## $sublista
## $sublista$a
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## 
## $nuevo_elem
##  [1]  1.69679092635824325 -0.88433743533715903  0.85648970146977699
##  [4]  0.17494245057415270 -0.39850496200257007  0.27520256239410407
##  [7] -1.26871879906914331 -0.01008132898571333  0.65340172450247769
## [10]  0.09857997949400066  0.90261694132495107 -0.51989749588921874
## [13] -1.29349097974465210 -0.04689771043879913 -0.63499626589402647
## [16] -0.21770227188875313 -1.57484166313679341 -0.27750315193029645
## [19]  0.55029220750056151 -0.61094661705016162 -2.13486545165556052
## [22]  0.69927743788382590  1.07719596695355735  0.86791815730251343
## [25] -0.79073937853598142 -0.10933017366165988 -0.93035006106079787
## [28] -0.36712126465207523 -0.89291430875059996 -0.35777280804279865

o bien

## $vector
##  [1] 0.8176385075785220 0.8938548327423632 0.6814558403566480
##  [4] 0.4533687653020024 0.6515468196012080 0.7260923418216407
##  [7] 0.6991440386045724 0.5504099403042346 0.8171223362442106
## [10] 0.2699587242677808
## 
## $pollitos_df
##    pollito_id lote       peso_inicial Dieta        peso_dieta
## 1           1   L1  8.544862350448966    D1 2249.397271513513
## 2           2   L1 11.758935921825469    D1 2250.660069387382
## 3           3   L1  8.705138908699155    D1 2252.050749526114
## 4           4   L1 11.278820903971791    D1 2250.490808178818
## 5           5   L1  8.048473510891199    D1 2248.268520581220
## 6           6   L1 10.560249282047153    D1 2250.710883659408
## 7           7   L1  9.068114688619971    D1 2250.013822911462
## 8           8   L1 10.277991003356874    D1 2248.598958402634
## 9           9   L1 11.861210129223764    D1 2251.259123665442
## 10         10   L1  8.793691774830222    D1 2249.872522481624
## 
## $sublista
## $sublista$a
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## 
## $nuevo_elem
##  [1]  1.69679092635824325 -0.88433743533715903  0.85648970146977699
##  [4]  0.17494245057415270 -0.39850496200257007  0.27520256239410407
##  [7] -1.26871879906914331 -0.01008132898571333  0.65340172450247769
## [10]  0.09857997949400066  0.90261694132495107 -0.51989749588921874
## [13] -1.29349097974465210 -0.04689771043879913 -0.63499626589402647
## [16] -0.21770227188875313 -1.57484166313679341 -0.27750315193029645
## [19]  0.55029220750056151 -0.61094661705016162 -2.13486545165556052
## [22]  0.69927743788382590  1.07719596695355735  0.86791815730251343
## [25] -0.79073937853598142 -0.10933017366165988 -0.93035006106079787
## [28] -0.36712126465207523 -0.89291430875059996 -0.35777280804279865
## 
## $nuevo_elem_2
##  [1] 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 1 1 1 0 0 1 0 1 1 0 0 1 1 1 1

Leyendo datos en R

Se pueden importar datos tabulados provenientes de varios formatos. Los más comunes son .csv,.txt y .xls. Los comandos para leer estos formatos son read.csv, read.table, read.xls (en el paquete gdata) y loadWorkbook (en el paquete XLConnect).

En este documento veremos cómo cargar datos con los comandos read.csv y read.table. El primero sirve para leer datos separados por comas y el segundo por tabulaciones.

Algunas bases de datos contienen otro tipo de separadores, tales como “;” “:” o cualquier otro caracter. Tanto read.csv como read.table tienen un argumento que perimite indicar el caracter sepador, este argumento es sep = "caracter". Así, si nuestra base de datos estuviera separada por “;”, sólo tendríamos que indicarlo de la siguiente manera: sep=";".

Veamos algunos ejemplos concretos.

  • Datos separados por comas
species long lat
bradypus_variegatus -65.40000000000001 -10.3833
bradypus_variegatus -65.38330000000001 -10.3833
bradypus_variegatus -65.13330000000001 -16.8000
bradypus_variegatus -63.66670000000000 -17.4500
bradypus_variegatus -63.85000000000000 -17.4000
bradypus_variegatus -64.41670000000001 -16.0000
  • Datos separados por tabulaciones
name longitude latitude issues
Ambystoma tigrinum -92.48258000000000 34.46026 cdround,gass84
Ambystoma tigrinum -95.88531999999999 31.93524 cdround,gass84
Ambystoma tigrinum -93.27306000000000 45.21076 cdround,gass84
Ambystoma tigrinum -96.32323000000000 44.00937 cdround,gass84
Ambystoma tigrinum -95.60391000000000 41.46921 cdround,gass84
Ambystoma tigrinum -97.75873000000000 35.26342 cdround,gass84
  • Usando read.csv para leer datos separados por tabulaciones
name longitude latitude issues
Ambystoma tigrinum -92.48258 34.46026 cdround,gass84
Ambystoma tigrinum -95.88532 31.93524 cdround,gass84
Ambystoma tigrinum -93.27306 45.21076 cdround,gass84
Ambystoma tigrinum -96.32323 44.00937 cdround,gass84
Ambystoma tigrinum -95.60391 41.46921 cdround,gass84
Ambystoma tigrinum -97.75873 35.26342 cdround,gass84

Nota: una cuestión que debemos de tomar en cuenta cuando leemos datos en R es la codificación de nuestro sistema, ya que esto puede causar que no podamos leer un archivo. Algunas de las codificaciones más frecuentes son: UTF-8 (default en MAC), ASCII, WINDOWS-1252 y las ISO-xxxx-x. En R podemos especificar la codificación con el argumento fileEncoding de las funciones read.csv y read.table

prov key datasetKey
gbif 1265535984 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1088947578 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1088946504 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1143544830 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1227733876 50c9509d-22c7-4a22-a47d-8c48425ef4a7
gbif 1252601766 2e64dedd-0996-4cd6-b6cd-4f055a46c38c

Un ejemplo de como leer archivos de Excel

Como se mencionó anteriormente, en R es posible leer archivos de Excel utilizando las funciones read.xls y loadWorkbook de los paquetes gdata y XLConnect respectivamente. Veamos cómo instalar estos paquetes para utilizar las funciones señaladas.

  • Con read.xls sólo tenemos que señalar la ruta donde se encuentra nuestro xls y la hoja del libro.
## gdata: read.xls support for 'XLS' (Excel 97-2004) files ENABLED.
## 
## gdata: read.xls support for 'XLSX' (Excel 2007+) files ENABLED.
## 
## Attaching package: 'gdata'
## The following object is masked from 'package:stats':
## 
##     nobs
## The following object is masked from 'package:utils':
## 
##     object.size
## The following object is masked from 'package:base':
## 
##     startsWith
IterationNo AUC_at_Value_0.95 AUC_at_0.5 AUC_ratio
1 0.6904844465485830 0.455461834131189 1.51600945415264
2 0.6502447312374160 0.440165890604005 1.47727196749648
3 0.7395332992408410 0.466813435453584 1.58421596953881
4 0.6904844465485830 0.455461834131189 1.51600945415264
5 0.7908706395783081 0.479626956033633 1.64892867181312
6 0.6259150694167050 0.433288054415460 1.44457033384203

Veamos cómo hacer lo anterior con el paquete XLConnect

## Loading required package: XLConnectJars
## XLConnect 0.2-15 by Mirai Solutions GmbH [aut],
##   Martin Studer [cre],
##   The Apache Software Foundation [ctb, cph] (Apache POI),
##   Graph Builder [ctb, cph] (Curvesapi Java library)
## http://www.mirai-solutions.com
## https://github.com/miraisolutions/xlconnect
## [1] "ROC"  "OCCS"
IterationNo AUC_at_Value_0.95 AUC_at_0.5 AUC_ratio
1 0.6904844465485830 0.455461834131189 1.51600945415264
2 0.6502447312374160 0.440165890604005 1.47727196749648
3 0.7395332992408410 0.466813435453584 1.58421596953881
4 0.6904844465485830 0.455461834131189 1.51600945415264
5 0.7908706395783081 0.479626956033633 1.64892867181312
6 0.6259150694167050 0.433288054415460 1.44457033384203

Estructuras de Control y Loops

Programar implica escribir instrucciones relativamente complejas y repetir de manera iterada algunas de ellas. Hay dos grandes tipos de programación:

  1. La programación imperativa en donde se le indica a la computadora de manera consecutiva un conjunto de operaciones.

  2. La programación declarativa en donde se da una descripción del resultado final (i.e HTML, \(\LaTeX\)) sin especificar cómo se obtiene tal resultado.

Dentro de cada uno de estos estilos generales hay subdivisiones y algunos programas pueden contener varios aspectos de ellos. De manera específica en R, podemos encontrar a la programación modular (paquetes), la orientada a objetos y funcional.

A continuación veremos unas estructuras conocidas como estructuras de control. Estas controlan cuántas veces una operación debe de repetirse.

La sentencia if

if es una sentencia cuya entrada es una operación de tipo lógica y nos permite probar si alguna condición se cumple o no. El diagrama de flujo para la sentencia if es el siguiente

La sintaxis if en R:

Imaginemos que nos interesa hacer un conjunto de operaciones sólo sobre los números divisibles entre 2 (pares) y descartar aquellos números que no son pares, a continuación veremos cómo utilizar if para lograr nuestro cometido.

## 1 No es par
## 2 Es par
## 3 No es par
## 4 Es par

for loop

Supongamos que saber cuáles son los números que son pares en un vector de 100 elementos; esto implicaría repetir 100 veces el código de la sección anterior. La sentencia for permite especificar con tan solo una pocas líneas de código operaciones que se repiten n veces.

La sintaxis del for loop en R es

##   [1] 533 414 331 330 523 345 429 327 508 353 283 442 360 254 387 479 297
##  [18] 433 316 223 168 438 261 422 348 217 271 214 201 362 241 311 303 321
##  [35] 402 401 439 493 545 478 542 340 437 383 299 259 371 302 430 260 507
##  [52] 286 436 281 510 301 325 407 535 425 513 242 364 369 293 417 517 418
##  [69] 235 494 249 547 380 519 204 412 416 243 323 421 245 454 165 188 239
##  [86] 209 393 515 389 232 525 484 169 441 390 216 213 288 207 287
## 533 No es par
## 414 Es par
## 331 No es par
## 330 Es par
## 523 No es par
## 345 No es par
## 429 No es par
## 327 No es par
## 508 Es par
## 353 No es par
## 283 No es par
## 442 Es par
## 360 Es par
## 254 Es par
## 387 No es par
## 479 No es par
## 297 No es par
## 433 No es par
## 316 Es par
## 223 No es par
## 168 Es par
## 438 Es par
## 261 No es par
## 422 Es par
## 348 Es par
## 217 No es par
## 271 No es par
## 214 Es par
## 201 No es par
## 362 Es par
## 241 No es par
## 311 No es par
## 303 No es par
## 321 No es par
## 402 Es par
## 401 No es par
## 439 No es par
## 493 No es par
## 545 No es par
## 478 Es par
## 542 Es par
## 340 Es par
## 437 No es par
## 383 No es par
## 299 No es par
## 259 No es par
## 371 No es par
## 302 Es par
## 430 Es par
## 260 Es par
## 507 No es par
## 286 Es par
## 436 Es par
## 281 No es par
## 510 Es par
## 301 No es par
## 325 No es par
## 407 No es par
## 535 No es par
## 425 No es par
## 513 No es par
## 242 Es par
## 364 Es par
## 369 No es par
## 293 No es par
## 417 No es par
## 517 No es par
## 418 Es par
## 235 No es par
## 494 Es par
## 249 No es par
## 547 No es par
## 380 Es par
## 519 No es par
## 204 Es par
## 412 Es par
## 416 Es par
## 243 No es par
## 323 No es par
## 421 No es par
## 245 No es par
## 454 Es par
## 165 No es par
## 188 Es par
## 239 No es par
## 209 No es par
## 393 No es par
## 515 No es par
## 389 No es par
## 232 Es par
## 525 No es par
## 484 Es par
## 169 No es par
## 441 No es par
## 390 Es par
## 216 Es par
## 213 No es par
## 288 Es par
## 207 No es par
## 287 No es par

Alternativamente

Ejemplos un poco más laboriosos

Supongan que ahora se les pide guardar en un vector los números que son pares y los que no lo son en otro (para números enteros son los impares).La idea para solucionar nuestro problema es simple, apliquemos el algoritmo par o impar y vayamos guardando (“rellenando”) los resultados en un vector nulo (vacío).

En el vector vec_pares se generaron de manera automática NAs (Not Aviable) cuando la condición es par no se cumplió (R lo hace de manera automática). Lo mismo ocurrió para el vector vec_impares cuando la otra condición no se cumplió (condición es impar).

Veamos cómo quitar los NAs.

##  [1] 414 330 508 442 360 254 316 168 438 422 348 214 362 402 478 542 340
## [18] 302 430 260 286 436 510 242 364 418 494 380 204 412 416 454 188 232
## [35] 484 390 216 288
##  [1] 533 331 523 345 429 327 353 283 387 479 297 433 223 261 217 271 201
## [18] 241 311 303 321 401 439 493 545 437 383 299 259 371 507 281 301 325
## [35] 407 535 425 513 369 293 417 517 235 249 547 519 243 323 421 245 165
## [52] 239 209 393 515 389 525 169 441 213 207 287

De forma similar podemos filtrar los datos con el comando is.na. Debido a que estamos interesados en los datos que no son NA usamos el comando de negación ! para preguntar cuáles no son NA. Finalmente, con el comando which podemos saber las posiciones del vector vec_pares que no son NA.

Si nos preguntaramos de nuestro vector original (vec_num) cuantos son pares y cuantos son impares…

## El numero de enteros pares en vec_num fue de 38
## El numero de enteros impares en vec_num fue de 62

while loop

Habrá situaciones donde no sabemos cuántas iteraciones exactas necesitamos para llegar a cierto resultado. Será necesario hacer los cálculos y evaluar el resultado en cada iteración hasta que la condición que buscamos se cumpla. En esta situaciones podemos ocupar el ciclo while.

Supongamos que se nos pide calcular cuál es el número de la sucesión de Fibonacci más cercano al 400. El algoritmo para encontrar el \(n-esimo\) término de la sucesión de Fibonacci es el siguiente

\[ f_{n} = f_{n-1} + f_{n-2}\,\,\text{para } n=2,3,4,5,...\] Se definen los primeros 2 números como \(f_0=0\) y \(f_1=1\). Por tanto \(f_2\) es

\[f_{2}=f_{1}+f_{0}=1+0=1\]

Ahora vemos cómo generar la secuencia de números de Fibonacci menores a 400 usando while.

##  [1]   0   1   1   2   3   5   8  13  21  34  55  89 144 233 377

¿Cuál es la posición del elemento de la sucesión más cercano a 400?

## [1] 15

Funciones definidas por el usuario.

Es común que hagamos ciertas operaciones de manera repetida y como consecuencia de ello tengamos que duplicar código que ya hemos ocupado con anterioridad. Lo anterior hace nuestros programas o scripts sean enormes y con mucha información redundante. Las funciones definidas por el usuarios precisamente están pensadas para que cuando tengamos que hacer una operación de manera repetida podamos llamar código con una sola instrucción sin tener que escribir todo nuevamente.

En R podemos definir nuestras propias funciones de manera fácil. Veremos cómo definir una función para pregruntar si un número entero es par o impar. Asimismo, definieremos una función para generar los primeros \(n\) números de la secuencia de Fibonacci.

La operaciones vectorizadas

Dentro de las críticas más fuertes que se le hacen a R es que es un lenguaje “lento”. Una de las razones de ello, es que al ser un leguaje interpretado, R pregunta el tipo de variable (integer, floating, char, etc) en el tiempo de ejecución, sus instrucciones se traducen o interpretan una a una, cada vez que se ejecuta el programa. Cuando asignamos un valor a una variable, digamos a <- 1.0 lo que hace el interprete de R es preguntar:

  • Ese número 1.0 es de tipo flotante
  • La variable a es de tipo numérica
  • Poner un lugar en la memoria donde almacenar el 1.0
  • Registar “a” como un puntero a ese lugar de memoria.

Para una explicación maravillosa sobre este tópico ver el artículo de Noam Ross

En los leguajes compliados (C, C++, fortran) declaramos los tipos de las variables desde un principio, sus instrucciones se traducen a código máquina de manera directa y optimizada mediante un compilador, lo que los hace más efecientes.

En R una forma de abordar el problema de eficiencia es utilizando operaciones vectorizadas siempre que sea posible. Las operaciones vectorizadas permiten a R llamar funciones de alto nivel que ejecutan código de C, lo que resulta en programas mucho más rápidos.

Comparemos el rendimiento de operaciones no vectorizadas vs. vectorizadas.

Operaciones no vectorizadas vs. vectorizadas.

Sea df_occs una base de datos con puntos de presencia de varias especies de reptiles y anfibios; suponga que se le pide filtar los datos de presencia por especie y contruir una lista donde cada elemento de ella es un data.frame que contiene los datos de cada especie. Veremos cómo hacer este filtrado utilizando operaciones no vectorizadas y vectorizadas. Haremos uso de la función system.time para medir el tiempo que tarde en correr los algoritmos…

Primero leemos la base de datos de los puntos de presencia y exploramos la base de datos (BD).

## [1] 4000    6
name longitude latitude prov date key
Sceloporus occidentalis -120.65935 37.8203800000000 gbif 2016-03-16 1262381503
Pseudacris regilla -121.98533 40.4388299990685 gbif 2003-06-25 543583266
Gehyra variegata 137.40600 -20.9770000000000 gbif 2009-04-12 1085956160
Lampropholis delicata 150.59459 -34.5286200331773 gbif 2012-04-01 1074452855
Zootoca vivipara 10.36416 59.9032500000000 gbif 2015-07-31 1238773985
Chamaeleo dilepis 29.45000 -23.8166700000000 gbif 1916-11-19 287041669
## [1] "name"      "longitude" "latitude"  "prov"      "date"      "key"
##   [1] Sceloporus occidentalis      Pseudacris regilla          
##   [3] Gehyra variegata             Lampropholis delicata       
##   [5] Zootoca vivipara             Chamaeleo dilepis           
##   [7] Rana pretiosa                Ctenotus taeniolatus        
##   [9] Egernia cunninghami          Anolis lemurinus            
##  [11] Psammodromus algirus         Craugastor fleischmanni     
##  [13] Anaxyrus debilis             Eremiascincus richardsonii  
##  [15] Tiliqua rugosa               Eurycea bislineata          
##  [17] Dipsosaurus dorsalis         Liolaemus bibronii          
##  [19] Desmognathus fuscus          Notechis scutatus           
##  [21] Austrelaps superbus          Egernia saxatilis           
##  [23] Anolis carolinensis          Sphaerodactylus nicholsi    
##  [25] Rana cascadae                Egernia striolata           
##  [27] Sceloporus undulatus         Sceloporus variabilis       
##  [29] Stellagama stellio           Lepidophyma flavimaculatum  
##  [31] Lacerta agilis               Bassiana duperreyi          
##  [33] Varanus varius               Pseudacris cadaverina       
##  [35] Ctenotus regius              Lithobates pipiens          
##  [37] Sceloporus graciosus         Amphibolurus muricatus      
##  [39] Xantusia vigilis             Incilius alvarius           
##  [41] Heteronotia binoei           Anaxyrus cognatus           
##  [43] Eleutherodactylus coqui      Takydromus sexlineatus      
##  [45] Uta stansburiana             Psammodromus hispanicus     
##  [47] Rhinella marina              Incilius marmoreus          
##  [49] Incilius mazatlanensis       Hemiergis decresiensis      
##  [51] Moloch horridus              Pseudonaja textilis         
##  [53] Plestiodon gilberti          Ctenotus uber               
##  [55] Liolaemus darwinii           Sphaerodactylus macrolepis  
##  [57] Lithobates warszewitschii    Platysaurus intermedius     
##  [59] Liolaemus koslowskyi         Tiliqua nigrolutea          
##  [61] Anolis humilis               Sceloporus malachiticus     
##  [63] Eremiascincus fasciolatus    Liolaemus kingii            
##  [65] Hemiergis peronii            Liolaemus quilmes           
##  [67] Pachymedusa dacnicolor       Lithobates palmipes         
##  [69] Sceloporus merriami          Dendrobates auratus         
##  [71] Anolis intermedius           Liopholis inornata          
##  [73] Parasuta flagellum           Liolaemus boulengeri        
##  [75] Anolis gundlachi             Podarcis muralis            
##  [77] Liolaemus robustus           Smilisca fodiens            
##  [79] Liolaemus tenuis             Liolaemus rothi             
##  [81] Liolaemus kriegi             Pseudemoia entrecasteauxii  
##  [83] Pseudemoia spenceri          Protobothrops mucrosquamatus
##  [85] Liolaemus fitzingerii        Lobulia elegans             
##  [87] Liolaemus pictus             Eulamprus kosciuskoi        
##  [89] Anolis cupreus               Liolaemus elongatus         
##  [91] Anolis cristatellus          Anaxyrus canorus            
##  [93] Tarentola boettgeri          Anolis lionotus             
##  [95] Takydromus septentrionalis   Hyla walkeri                
##  [97] Anolis tropidolepis          Liolaemus petrophilus       
##  [99] Anolis cooki                 Sphaerodactylus klauberi    
## [101] Liolaemus chacoensis         Liolaemus multimaculatus    
## [103] Phymaturus patagonicus       Liolaemus scapularis        
## [105] Liolaemus melanops           Liolaemus olongasta         
## [107] Liolaemus tari               Liolaemus walkeri           
## [109] Rankinia diemensis          
## 109 Levels: Amphibolurus muricatus Anaxyrus canorus ... Zootoca vivipara

Algoritmo de búsqueda no vectorizado

Primero definimos la lista en donde guardaremos los data.frames de cada especie. Nótese que la lista tendrá tantos elementos como especies en la BD.

Ahora implementamos el algorimo de búsqueda. La idea básica es ir recorriendo toda la columana name de la base de datos occs_bd e ir preguntando cuál registro cumple la condición occs_bd$name == sp_name_i; posteriormente almacenar estos índices en un vector llamado sp_index con los índices que cumplen la condición. Finalemente hacer un subset de occs_bd con sp_index.

Cuánto tardó en correr?

##    user  system elapsed 
##  14.897   0.132  15.139

Algoritmo de búsqueda vectorizado

Utilizaremos un comando de mi lista de estrellas, este es which

Combinamos la operación vectorizada which con el ciclo for

Cuánto tardo con el vectorizado??

##                user              system             elapsed 
## 0.02200000000000202 0.00000000000000000 0.02299999999999969

Cuántas veces corrió más rápido el código vectorizado?

## [1] 658.2173913043567

La familia apply

La familia de funciones apply tienen como objetivo operar sobre estructuras de datos como matrix, data.frames, arrays, y lists de forma repetitiva. Estas funciones aplican una función sobre un conjunto de datos y devulven un arreglo el cual puede ser una matriz, una tabla de datos o una lista. Una característica de ellas, es que permiten evitar los loops, por lo que serán necesarias menos lineas de código para llegar a un mismo resultado (el código suele ser más elegante).

Entre los R-programadores se suele decir que es más R-tónico (en alusión a pythonico) utilizar las funciones de la familia apply sobre los loops.

Veamos cuales funciones conforman esta familia y sus ouputs (es información la tomé de esta página):

Función
base::apply Apply Functions Over Array Margins
base::by Apply a Function to a Data Frame Split by Factors
base::eapply Apply a Function Over Values in an Environment
base::lapply Apply a Function over a List or Vector
base::mapply Apply a Function to Multiple List or Vector Arguments
base::rapply Recursively Apply a Function to a List
base::tapply Apply a Function Over a Ragged Array

lapply

La función lappy regresa una lista cuyos elementos pueden ser cualquier tipo de estructura de datos (matrix, data.frames, arrays, lists, etc.).

Veremos cómo implementar nuestro algortimo de búsqueda y filtrado de datos por especie utilizando las apply functions.

Como se había mencionado anteriormente las funciones de esta gran familia aplican una función (generalmente definida por el usuario) sobre una estructura de datos y por lo tanto, para implementar nuestro algoritmo de búsqueda será necesario definir nuestra función.

Apliquemos nuestra función usando la sintaxis lapply. En esta sólo hay que especificar un vector de índices o listas (X) sobre el cual la función que definimos va a operar (find_sp).

Usando una funcón que llama c

Comparemos los rendimientos de nuestras implementaciones:

## Tiempo de ejecucion: 15.139 algoritmo no vectorizado
## Tiempo de ejecucion: 0.02299999999999969 algoritmo vectorizado
## Tiempo de ejecucion: 0.03999999999999915 algoritmo vectorizado y lappy
## Tiempo de ejecucion: 0.01099999999999923 split

purrr programación funcional

La idea es mapear una los elementos de una lista y aplicar una función. Calculemos el polígono convexo de los puntos de presencia de las especies

  • Primero creamos la función para estimar los puntos que formaran el polígono convexo.
  • Convertimos en una lista el data.frame de la base de datos de presencia

Graficaremos los polígonos convexos de 5 especies tomadas al azar

## $`Liolaemus kriegi`
## NULL
## 
## $`Hemiergis decresiensis`
## NULL
## 
## $`Sceloporus variabilis`
## NULL
## 
## $`Lobulia elegans`
## NULL
## 
## $`Zootoca vivipara`
## NULL

Pauqetes usados durante este tutorial

## R version 3.5.1 (2018-07-02)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS High Sierra 10.13.6
## 
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] XLConnect_0.2-15     XLConnectJars_0.2-15 gdata_2.18.0        
## [4] knitr_1.21           dygraphs_1.1.1.6    
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.0       compiler_3.5.1   later_0.7.5      questionr_0.7.0 
##  [5] highr_0.7        rmdformats_0.3.3 tools_3.5.1      xts_0.10-2      
##  [9] digest_0.6.18    jsonlite_1.6     evaluate_0.12    lattice_0.20-35 
## [13] rlang_0.3.1      shiny_1.2.0      rstudioapi_0.7   yaml_2.2.0      
## [17] xfun_0.4         rJava_0.9-10     stringr_1.3.1    htmlwidgets_1.2 
## [21] gtools_3.8.1     grid_3.5.1       R6_2.3.0         rmarkdown_1.11  
## [25] bookdown_0.7     purrr_0.2.5      magrittr_1.5     promises_1.0.1  
## [29] htmltools_0.3.6  mime_0.6         xtable_1.8-3     httpuv_1.4.5    
## [33] stringi_1.2.4    miniUI_0.1.1.1   zoo_1.8-3

Luis Osorio Olvera ()

2019-01-24